package com.yz.fanrenmianshi.blackfilter;

import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
// todo 取消注释开启 Nacos（须先配置 Nacos）
// 当前已禁用Nacos，使用本地文件配置
//@Component
public class NacosListener implements InitializingBean {

    @NacosInjected
    private ConfigService configService;

    @Value("${nacos.config.data-id}")
    private String dataId;

    @Value("${nacos.config.group}")
    private String group;
    
    // 重试配置
    @Value("${blackip.nacos.retry.max-attempts:3}")
    private int maxRetryAttempts;
    
    @Value("${blackip.nacos.retry.delay:5000}")
    private long retryDelay;
    
    private final ScheduledExecutorService retryExecutor = 
        Executors.newSingleThreadScheduledExecutor(r -> {
            Thread t = new Thread(r, "nacos-retry-thread");
            t.setDaemon(true);
            return t;
        });

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("nacos 监听器启动");
        
        // 带重试的初始化
        initWithRetry();
    }
    
    private void initWithRetry() {
        int attempts = 0;
        while (attempts < maxRetryAttempts) {
            try {
                String config = configService.getConfigAndSignListener(dataId, group, 3000L, 
                    createConfigListener());
                
                // 初始化黑名单
                BlackIpUtils.rebuildBlackIp(config);
                log.info("Nacos配置获取成功，黑名单初始化完成");
                return;
                
            } catch (Exception e) {
                attempts++;
                log.error("Nacos配置获取失败，第{}次尝试", attempts, e);
                
                if (attempts >= maxRetryAttempts) {
                    log.error("Nacos配置获取失败，已达到最大重试次数，启用降级策略");
                    // 触发降级策略
                    BlackIpUtils.rebuildBlackIp(null);
                    
                    // 启动后台重试任务
                    startBackgroundRetry();
                    return;
                }
                
                try {
                    Thread.sleep(retryDelay * attempts); // 指数退避
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }
    }
    
    private Listener createConfigListener() {
        return new Listener() {
            final ThreadFactory threadFactory = new ThreadFactory() {
                private final AtomicInteger poolNumber = new AtomicInteger(1);
                
                @Override
                public Thread newThread(@NotNull Runnable r) {
                    Thread thread = new Thread(r);
                    thread.setName("refresh-ThreadPool" + poolNumber.getAndIncrement());
                    return thread;
                }
            };
            final ExecutorService executorService = Executors.newFixedThreadPool(1, threadFactory);
            
            @Override
            public Executor getExecutor() {
                return executorService;
            }
            
            @Override
            public void receiveConfigInfo(String configInfo) {
                try {
                    log.info("监听到配置信息变化：{}", configInfo);
                    BlackIpUtils.rebuildBlackIp(configInfo);
                } catch (Exception e) {
                    log.error("处理配置变化失败", e);
                    // 配置变化处理失败时，保持当前黑名单不变
                }
            }
        };
    }
    
    // 后台重试任务
    private void startBackgroundRetry() {
        retryExecutor.scheduleWithFixedDelay(() -> {
            try {
                log.info("尝试重新连接Nacos获取最新配置");
                String config = configService.getConfig(dataId, group, 3000L);
                BlackIpUtils.rebuildBlackIp(config);
                log.info("Nacos重连成功，黑名单已更新");
            } catch (Exception e) {
                log.debug("Nacos重连失败，将继续重试", e);
            }
        }, 60, 60, TimeUnit.SECONDS); // 每60秒重试一次
    }
}